/*
 * 字符串工具函数：StringUtil
 *
 * isEmpty(str: string)
 * isNotEmpty(str: string)
 * trim(str: string)
 * startsWith(str: string, prefix: string)
 * endsWith(str: string, suffix: string)
 * repeat(str: string, count: number)
 *
 * 集合工具函数：CollectionUtil
 *
 * isEmpty(collection: any)
 * isNotEmpty(collection: any)
 *
 * 树工具函数：TreeUtil
 *
 * findNodeInTree(treeOptions: TreeOption[], targetId: string)
 *
 * 业务函数：BizUtil，这一般是框架级的，对于公共资源的操作
 *
 * org.toTreeSelectOptions()
 */

import type { TreeOption } from 'naive-ui';

export const StringUtil = {
  /*
   * [功能] 判断字符串是否为空或仅包含空白字符
   * [说明] 如果字符串为 null、undefined 或仅包含空白字符，则返回 true；否则返回 false
   */
  isEmpty: (str: string | null | undefined): boolean => {
    // 首先检查字符串是否为 null 或 undefined
    if (str === null || str === undefined) {
      return true;
    }

    // 去除字符串首尾的空白字符后，检查是否为空字符串
    return str.trim() === '';
  },
  /*
   * [功能] 判断字符串是否非空（不能仅包含空白字符）
   * [说明] 如果字符串为 null、undefined 或仅包含空白字符，则返回 true；否则返回 false
   */
  isNotEmpty: (str: string | null | undefined): boolean => {
    return !StringUtil.isEmpty(str);
  },
  /*
   * [功能] 去除字符串首尾的空白字符
   * [说明] 如果字符串不为 null 或 undefined，则返回去除首尾空白字符后的字符串；否则返回原字符串
   */
  trim: (str: string | null | undefined): string | null | undefined => {
    // 检查字符串是否为 null 或 undefined
    if (str === null || str === undefined) {
      return str;
    }

    // 调用字符串的 trim 方法去除首尾空白字符
    return str.trim();
  },

  /*
   * [功能] 判断字符串是否以指定的前缀开头
   * [说明] 如果字符串不为 null 或 undefined 且以指定前缀开头，则返回 true；否则返回 false
   */
  startsWith: (str: string | null | undefined, prefix: string): boolean => {
    // 检查字符串是否为 null 或 undefined
    if (str === null || str === undefined) {
      return false;
    }

    // 调用字符串的 startsWith 方法检查是否以指定前缀开头
    return str.startsWith(prefix);
  },

  /*
   * [功能] 判断字符串是否以指定的后缀结尾
   * [说明] 如果字符串不为 null 或 undefined 且以指定后缀结尾，则返回 true；否则返回 false
   */
  endsWith: (str: string | null | undefined, suffix: string): boolean => {
    // 检查字符串是否为 null 或 undefined
    if (str === null || str === undefined) {
      return false;
    }

    // 调用字符串的 endsWith 方法检查是否以指定后缀结尾
    return str.endsWith(suffix);
  },

  /*
   * [功能] 将字符串重复指定的次数
   * [说明] 如果字符串不为 null 或 undefined 且重复次数为非负整数，则返回重复后的字符串；否则返回原字符串
   */
  repeat: (str: string | null | undefined, count: number): string | null | undefined => {
    // 检查字符串是否为 null 或 undefined
    if (str === null || str === undefined) {
      return str;
    }

    // 检查重复次数是否为非负整数
    if (Number.isInteger(count) && count >= 0) {
      // 调用字符串的 repeat 方法重复指定次数
      return str.repeat(count);
    }

    // 如果重复次数不符合要求，返回原字符串
    return str;
  },
  join: (arr: any, separator = ',') => {
    if (arr === null || arr === undefined) {
      return '';
    }
    if (!Array.isArray(arr)) {
      return '';
    }
    if (separator === null || separator === undefined) {
      return '';
    }
    if (typeof separator !== 'string') {
      return '';
    }
    let result = '';
    for (let i = 0; i < arr.length; i += 1) {
      if (i > 0) {
        result += separator;
      }
      result += String(arr[i]);
    }
    return result;
  }
};

export const CollectionUtil = {
  /*
   * [功能] 判断一个集合是否为空
   * [说明] 支持的集合类型包括：数组（Array）、集合（Set）、映射（Map）
   */
  isEmpty: (collection: any): boolean => {
    // 检查是否为 null 或 undefined
    if (collection === null || collection === undefined) {
      return true;
    }

    // 检查是否为数组
    if (Array.isArray(collection)) {
      return collection.length === 0;
    }

    // 检查是否为 Set
    if (collection instanceof Set) {
      return collection.size === 0;
    }

    // 检查是否为 Map
    if (collection instanceof Map) {
      return collection.size === 0;
    }

    // 如果不是上述支持的集合类型，返回 false
    return false;
  },
  /*
   * [功能] 判断一个集合是否不为空
   * [说明] 支持的集合类型包括：数组（Array）、集合（Set）、映射（Map）
   */
  isNotEmpty: (collection: any): boolean => {
    return !CollectionUtil.isEmpty(collection);
  }
};

export const TreeUtil = {
  /*
   * [功能] 在树形结构数据中查找指定 key 的节点
   * [说明] 如果找到目标节点，则返回该节点对象；若未找到，则返回 null
   */
  findNodeInTree: (treeOptions: TreeOption[], targetId: string): TreeOption | null => {
    // 遍历树形结构的每一个节点
    for (const option of treeOptions) {
      // 检查当前节点的 key 是否等于目标 key
      if (option.key === targetId) {
        // 如果相等，说明找到了目标节点，直接返回该节点
        return option;
      }
      // 检查当前节点是否有子节点
      if (option.children && option.children.length > 0) {
        // 递归调用 findNodeInTree 函数，在当前节点的子节点中继续查找目标节点
        const found = TreeUtil.findNodeInTree(option.children, targetId);
        // 如果在子节点中找到了目标节点
        if (found) {
          // 返回找到的目标节点
          return found;
        }
      }
    }
    return null;
  },
  /*
   * [功能] 在树形结构数据中查找指定 key 的节点
   * [说明] 如果找到目标节点，则返回该节点对象；若未找到，则返回 null
   */
  findNodeInOrgTree: (OrgUnitTrees: Api.SystemManage.OrgUnitTree[], orgId: string): Api.SystemManage.OrgUnitTree | null => {
    // 遍历树形结构的每一个节点
    for (const org of OrgUnitTrees) {
      // 检查当前节点的 key 是否等于目标 key
      if (org.id === orgId) {
        // 如果相等，说明找到了目标节点，直接返回该节点
        return org;
      }
      // 检查当前节点是否有子节点
      if (org.children && org.children.length > 0) {
        // 递归调用 findNodeInTree 函数，在当前节点的子节点中继续查找目标节点
        const found = TreeUtil.findNodeInOrgTree(org.children, orgId);
        // 如果在子节点中找到了目标节点
        if (found) {
          // 返回找到的目标节点
          return found;
        }
      }
    }
    return null;
  }
};

export const ObjUtil = {
  /*
   * [功能] 克隆一个对象
   * [说明] 克隆后的对象或数组，如果传入的对象无法克隆，则返回 null
   */
  clone: (obj: any): any => {
    if (obj === null || obj === undefined) {
      return null;
    }
    if (typeof obj !== 'object') {
      return obj;
    }
    return JSON.parse(JSON.stringify(obj));
  },
  /*
   * [功能] 浅拷贝一个对象，忽略某些字段
   * [说明] 克隆后的对象或数组，如果传入的对象无法克隆，则返回 null
   */
  assignIgnoring(target: any, source: any, ignoreKeys: any = []) {
    Object.keys(source).forEach(key => {
      if (!ignoreKeys.includes(key)) {
        target[key] = source[key];
      }
    });
    return target;
  }
};

export const downloadFile = (fileName: string, blob: any) => {
  const aLink = document.createElement('a');
  // const blob = blob; // new Blob([content]);
  const evt = document.createEvent('HTMLEvents');
  // Loss last two parameters, an error is reported in FF,
  // 1. Event Type 2. Bubbling or not 3. Whether to block the browser's default behavior.
  evt.initEvent('click', true, true);
  aLink.download = fileName;
  aLink.href = URL.createObjectURL(blob);
  // Compatible with firefox
  aLink.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));

};
